/**************************************************************************** 
 * Meta，一个轻量级的静态分区Hypervisor 
 *
 * 版权(c) , 2022-
 *
 * 作者:
 *      Tupelo Shen <shenwanjiang2013@163.com>
 *
 * Meta是一个自由软件，你可以在遵循GNU GPLv2协议的条件下，重新修改并发布它。
 *
 ***************************************************************************/

#ifndef __CPU_H__
#define __CPU_H__

#include <meta.h>
#include <arch/cpu.h>

#include <spinlock.h>
#include <mem.h>
#include <list.h>

#define STACK_SIZE (PAGE_SIZE)

#ifndef __ASSEMBLER__

extern uint8_t _cpu_if_base;

struct cpuif {
    struct list event_list;

} __attribute__((aligned(PAGE_SIZE)));

struct vcpu;

struct cpu {
    cpuid_t id;
    struct addr_space as;

    struct vcpu* vcpu;

    struct cpu_arch arch;

    /** 修订历史：
     *      1.  PT_SIZE → HYP_ROOT_PT_SIZE （2023-06-01 Tupelo Shen）
     */
    pte_t root_pt[HYP_ROOT_PT_SIZE/sizeof(pte_t)] __attribute__((aligned(HYP_ROOT_PT_SIZE)));

    uint8_t stack[STACK_SIZE] __attribute__((aligned(PAGE_SIZE)));

    /******************* PUBLIC INTERFACE  **************************/

    struct cpuif interface __attribute__((aligned(PAGE_SIZE)));

} __attribute__((aligned(PAGE_SIZE)));

extern struct cpu cpu;

/*********************** 核间中断处理函数相关声明 ***************************/
/* 核间中断传递的消息数据结构 */
struct cpu_msg {
    uint32_t handler;
    uint32_t event;
    uint64_t data;
};

/* 核间中断发送消息 */
void cpu_send_msg(cpuid_t cpu, struct cpu_msg* msg);

/* 核间中断消息处理程序 */
typedef void (*cpu_msg_handler_t)(uint32_t event, uint64_t data);
#define CPU_MSG_HANDLER(handler, handler_id)                    \
    __attribute__((section(".ipi_cpumsg_handlers"), used))      \
        cpu_msg_handler_t __cpumsg_handler_##handler = handler; \
    __attribute__((section(".ipi_cpumsg_handlers_id"),          \
                   used)) volatile const size_t handler_id;

struct cpu_synctoken {
    spinlock_t          lock;
    volatile uint64_t   n;
    volatile bool       ready;
    volatile uint64_t   count;
};

extern struct cpu_synctoken cpu_glb_sync;

static inline void cpu_sync_init(struct cpu_synctoken* token, size_t n)
{
    token->lock = SPINLOCK_INITVAL;
    token->n = n;
    token->count = 0;
    token->ready = true;
}

/**
 * 功能描述: cpu核同步屏障
 *           cpu核通过对一个全局变量（计数器）进行自加操作，
 *           然后与核数进行比较，如果小于核数，则在此循环等待；
 *           如果大于等于核数，则说明所有的核都已经执行过自加操作，
 *           可以跳出该函数的循环等待，继续往下执行。
 * 入口参数: token,     同步令牌
 * 出口参数: void
 * 返 回 值: void
 * 修改日期: 2022-09-21
 */
static inline void cpu_sync_barrier(struct cpu_synctoken* token)
{
    // TODO: no fence/barrier needed in this function?

    size_t next_count = 0;

    while (!token->ready);

    spin_lock(&token->lock);
    token->count++;
    next_count = ALIGN(token->count, token->n);
    spin_unlock(&token->lock);

    while (token->count < next_count);
}

static inline struct cpuif* cpu_if(cpuid_t cpu_id)
{
    return (struct cpuif*)(((vaddr_t)&_cpu_if_base) +
           (cpu_id * ALIGN(sizeof(struct cpuif), PAGE_SIZE)));
}

/****************************************************************************
 ****                       公共函数接口                                 ****
 ****************************************************************************/
void cpu_init(cpuid_t cpu_id, paddr_t load_addr);
// void cpu_send_msg(cpuid_t cpu, struct cpu_msg* msg);
// bool cpu_get_msg(struct cpu_msg* msg);
void cpu_msg_handler();
// void cpu_msg_set_handler(cpuid_t id, cpu_msg_handler_t handler);
void cpu_idle(void);
void cpu_idle_wakeup(void);

void cpu_arch_init(cpuid_t cpu_id, paddr_t load_addr);
void cpu_arch_idle(void);

#endif /* __ASSEMBLER__ */

#endif /* __CPU_H__ */
